﻿using System;
using System.Configuration;
using System.Collections.Generic;
using System.Linq;
using System.Data.Linq;
using Hxsoft.AppV1;

namespace Hxsoft.AppV1.Module
{
	public partial class Comment : ICreator { }




	/// <summary>
	/// Comments 类。
	/// </summary>
	public static partial class Comments
	{
		public const string INFO_TYPE = "Comment";
		private static string CommentQuoteTemplate = StringExtensions.GetEffectiveValueOrDefault(ConfigurationManager.AppSettings["CommentQuoteTemplate"], "<div class=\"quoteBox\"><div class=\"quoteAuthor\">网友 ({PostIp}) 的原贴</div><div class=\"quoteContent\">{Quote}{Content}</div></div>");




		#region GetItem
		/// <summary>
		/// 根据标识获取指定的评论。
		/// </summary>
		/// <param name="o">评论集合。</param>
		/// <param name="commentId">获取的评论标识 CommentId。</param>
		/// <returns>获取的信息项。</returns>
		public static Comment GetItem(this System.Data.Linq.Table<Comment> o, int commentId)
		{
			return o.SingleOrDefault(p => p.CommentId == commentId);
		}

		public static Comment GetItem(int commentId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;
			return dc.Comments.GetItem(commentId);
		}
		#endregion



		#region Exists
		/// <summary>
		/// 验证指定的评论是否已经存在。
		/// </summary>
		/// <param name="o">评论集合。</param>
		/// <param name="commentId">验证的评论标识 CommentId。</param>
		/// <returns>布尔值表示指定的评论是否已经存在。</returns>
		public static bool Exists(this System.Data.Linq.Table<Comment> o, int commentId)
		{
			return o.Any(p => p.CommentId == commentId);
		}
		#endregion




		#region GetClientGetCommentQuoteScript
		public static string GetClientGetCommentQuoteScript()
		{
			return @"function(postIp, quote, content)
{
	return """ + StringExtensions.ToJavascriptString(CommentQuoteTemplate) + @""".replace(""{PostIp}"", postIp).replace(""{Quote}"", quote).replace(""{Content}"", content);
}";
		}
		#endregion



		#region GetMaskIp
		public static string GetMaskIp(string sourceIp)
		{
			string ip = sourceIp;
			if (string.IsNullOrEmpty(ip)) return ip;

			int index = ip.LastIndexOf('.');
			if (index == -1) return ip;
			return ip.Substring(0, index + 1) + "*";
		}
		#endregion
	}



	/// <summary>
	/// Comments 类操作部分。
	/// </summary>
	public static partial class Comments
	{
		#region Post
		/// <summary>
		/// 发表评论。
		/// </summary>
		/// <param name="postedComment">发表的评论。</param>
		/// <returns>发表的评论。</returns>
		public static Comment Post(Comment postedComment)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Comment comment = postedComment.ToNewEntity<Comment>();
			comment.PostTime = DateTime.Now;
			comment.CreatorId = Users.CurrentUserId;
			comment.IsEffective = OverallControl.GetSkipReviewRight(dc, comment, false);

			if (comment.QuoteId.HasValue)
			{
				Comment qComment = dc.Comments.GetItem(comment.QuoteId.Value);
				if (qComment != null)
				{
					string userName = null;
					if (qComment.CreatorId.HasValue)
					{
						userName = Users.GetUserName(qComment.CreatorId.Value);
					}
					comment.Quote = CommentQuoteTemplate.Replace("{PostIp}", string.IsNullOrEmpty(userName) ? GetMaskIp(qComment.PostIp) : userName)
						.Replace("{Quote}", qComment.Quote)
						.Replace("{Content}", Hxsoft.StringExtensions.HtmlEncode(qComment.Content));
				}
			}

			GetPostRight(dc, comment, true);	// 权限验证

			dc.Comments.InsertOnSubmit(comment);
			dc.SubmitChanges();

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Post, INFO_TYPE, comment.CommentId.ToString(), PermissionCode.Post.ToString(), StringExtensions.CutString(comment.Content, 300, "..."));

			// 返回只读数据
			return postedComment.FillByEntity(comment);
		}
		#endregion



		#region Update
		private static readonly HashSet<string> _updatedColumns = typeof(Comment).GetEntityColumnNames(new string[] {
				"IsEffective",
				"Content",
				"Quote",
				"IsAnonymity"
			}, true);

		/// <summary>
		/// 修改评论项。
		/// </summary>
		/// <param name="updatedComment">修改的评论项。</param>
		/// <returns>修改的评论项。</returns>
		public static Comment Update(Comment updatedComment)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Comment comment = dc.Comments.GetItem(updatedComment.CommentId);
			if (comment == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetUpdateRight(dc, comment, true);	// 权限验证

			comment.FillByEntity(updatedComment, _updatedColumns);

			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Update, INFO_TYPE, comment.CommentId.ToString(), PermissionCode.Update.ToString(), StringExtensions.CutString(comment.Content, 300, "..."));

			// 返回只读数据
			return updatedComment.FillByEntity(comment);
		}
		#endregion



		#region Delete
		/// <summary>
		/// 删除评论。
		/// </summary>
		/// <param name="commentId">删除的评论标识 CommentId。</param>
		public static void Delete(int commentId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Comment comment = dc.Comments.GetItem(commentId);
			if (comment == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetDeleteRight(dc, comment, true);	// 权限验证

			Delete(dc, comment);

			dc.SubmitChanges();

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Delete, INFO_TYPE, comment.CommentId.ToString(), PermissionCode.Delete.ToString(), StringExtensions.CutString(comment.Content, 300, "..."));
		}

		#region internal Delete
		internal static void Delete(GenericModuleDataContext dc, Comment comment)
		{
			dc.Comments.DeleteOnSubmit(comment);
		}
		#endregion
		#endregion



		#region SetEffectiveState
		/// <summary>
		/// 设置信息的有效状态。
		/// </summary>
		/// <param name="commentId">设置的信息标识。</param>
		public static void SetEffectiveState(int commentId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Comment comment = dc.Comments.GetItem(commentId);
			if (comment == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetSetEffectiveStateRight(dc, comment, true);	// 权限验证

			comment.IsEffective = !comment.IsEffective;
			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Setting, INFO_TYPE, comment.CommentId.ToString(), PermissionCode.Setting.ToString() + "/EffectiveState", StringExtensions.CutString(comment.Content, 300, "..."));
		}

		/// <summary>
		/// 设置信息的有效状态。
		/// </summary>
		/// <param name="commentId">设置的信息标识。</param>
		/// <param name="state">设置的状态。</param>
		public static void SetEffectiveState(int commentId, bool state)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();

			Comment comment = dc.Comments.GetItem(commentId);
			if (comment == null)
				throw new ObjectNotExistsException(Res.Operation_ObjectNotExists);

			GetSetEffectiveStateRight(dc, comment, true);	// 权限验证

			if (comment.IsEffective == state)
				return;

			comment.IsEffective = state;
			try
			{
				dc.SubmitChanges(ConflictMode.ContinueOnConflict);
			}
			catch (ChangeConflictException e)
			{
				foreach (ObjectChangeConflict occ in dc.ChangeConflicts)
				{
					occ.Resolve(RefreshMode.KeepCurrentValues);
				}
			}

			// 记录日志
			Logs.Insert(dc, ResourceId, (int)PermissionCode.Setting, INFO_TYPE, comment.CommentId.ToString(), PermissionCode.Setting.ToString() + "/EffectiveState", StringExtensions.CutString(comment.Content, 300, "..."));
		}
		#endregion




		#region 注册评论字典类别
		public static readonly DicClass CommentDicClass = RegisterDicClass();

		public const int CommentDicClassId = 10;
		public const string CommentDicClassCode = "InfoCommentType";
		/// <summary>
		/// 注册评论字典类别。
		/// </summary>
		public static DicClass RegisterDicClass()
		{
			DicClass info = new DicClass();
			info.ClassId = CommentDicClassId;
			info.ClassName = "信息评论类别";
			info.ClassCode = CommentDicClassCode;
			info.Memo = "";
			info.SiteId = null;

			return DicClasses.Register(info);
		}
		#endregion
	}



	/// <summary>
	/// Comments 类对应操作权限部分。（受限站点资源。）
	/// </summary>
	public static partial class Comments
	{
		#region GetPostRight
		/// <summary>
		/// 获取当前用户是否有发表评论的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="comment">发表的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有发表评论的权限。</returns>
		public static bool GetPostRight(GenericModuleDataContext dc, Comment comment, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Post;
			bool b = dc.AccessController.GetUserIsHasPermission<Comment>(userName, comment, ResourceId, permissionCode, comment.SiteId);

			if (triggerException && !b)
				throw new PermissionException(userName, comment, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有发表评论的权限。
		/// </summary>
		/// <param name="comment">发表的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有发表评论的权限。</returns>
		public static bool GetPostRight(Comment comment, bool triggerException)
		{
			return GetPostRight(new GenericModuleDataContext(), comment, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有发表评论的权限。
		/// </summary>
		/// <param name="comment">发表的评论对象。</param>
		/// <returns>布尔值表示当前用户是否有发表评论的权限。</returns>
		public static bool GetPostRight(Comment comment)
		{
			return GetPostRight(comment, false);
		}
		#endregion



		#region GetUpdateRight
		/// <summary>
		/// 获取当前用户是否有修改评论的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="comment">修改的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有修改评论的权限。</returns>
		public static bool GetUpdateRight(GenericModuleDataContext dc, Comment comment, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Update;
			bool b = dc.AccessController.GetUserIsHasPermission<Comment>(userName, comment, ResourceId, permissionCode, comment.SiteId);

			if (triggerException && !b)
				throw new PermissionException(userName, comment, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有修改评论的权限。
		/// </summary>
		/// <param name="comment">修改的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有修改评论的权限。</returns>
		public static bool GetUpdateRight(Comment comment, bool triggerException)
		{
			return GetUpdateRight(new GenericModuleDataContext(), comment, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有修改评论的权限。
		/// </summary>
		/// <param name="comment">修改的评论对象。</param>
		/// <returns>布尔值表示当前用户是否有修改评论的权限。</returns>
		public static bool GetUpdateRight(Comment comment)
		{
			return GetUpdateRight(comment, false);
		}
		#endregion



		#region GetDeleteRight
		/// <summary>
		/// 获取当前用户是否有删除评论的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="comment">删除的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有删除评论的权限。</returns>
		public static bool GetDeleteRight(GenericModuleDataContext dc, Comment comment, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Delete;
			bool b = dc.AccessController.GetUserIsHasPermission<Comment>(userName, comment, ResourceId, permissionCode, comment.SiteId);

			if (triggerException && !b)
				throw new PermissionException(userName, comment, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有删除评论的权限。
		/// </summary>
		/// <param name="comment">删除的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有删除评论的权限。</returns>
		public static bool GetDeleteRight(Comment comment, bool triggerException)
		{
			return GetDeleteRight(new GenericModuleDataContext(), comment, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有删除评论的权限。
		/// </summary>
		/// <param name="comment">删除的评论对象。</param>
		/// <returns>布尔值表示当前用户是否有删除评论的权限。</returns>
		public static bool GetDeleteRight(Comment comment)
		{
			return GetDeleteRight(comment, false);
		}
		#endregion



		#region GetSettingRight
		/// <summary>
		/// 获取当前用户是否有设置评论的权限。
		/// </summary>
		/// <param name="dc">数据容器。</param>
		/// <param name="comment">设置的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有设置评论的权限。</returns>
		public static bool GetSettingRight(GenericModuleDataContext dc, Comment comment, bool triggerException)
		{
			string userName = Users.CurrentUserName;
			int permissionCode = (int)PermissionCode.Setting;
			bool b = dc.AccessController.GetUserIsHasPermission<Comment>(userName, comment, ResourceId, permissionCode);

			if (triggerException && !b)
				throw new PermissionException(userName, comment, ResourceId, permissionCode, Res.PermissionExceptionMessage);
			return b;
		}

		/// <summary>
		/// 获取当前用户是否有设置评论的权限。
		/// </summary>
		/// <param name="comment">设置的评论对象。</param>
		/// <param name="triggerException">当未通过权限验证的时候是否引发异常。</param>
		/// <returns>布尔值表示当前用户是否有设置评论的权限。</returns>
		public static bool GetSettingRight(Comment comment, bool triggerException)
		{
			return GetSettingRight(new GenericModuleDataContext(), comment, triggerException);
		}

		/// <summary>
		/// 获取当前用户是否有设置评论的权限。
		/// </summary>
		/// <param name="comment">设置的评论对象。</param>
		/// <returns>布尔值表示当前用户是否有设置评论的权限。</returns>
		public static bool GetSettingRight(Comment comment)
		{
			return GetSettingRight(comment, false);
		}



		public static bool GetSetEffectiveStateRight(GenericModuleDataContext dc, Comment comment, bool triggerException)
		{
			return GetSettingRight(dc, comment, triggerException);
		}

		public static bool GetSetEffectiveStateRight(Comment comment, bool triggerException)
		{
			return GetSetEffectiveStateRight(new GenericModuleDataContext(), comment, triggerException);
		}

		public static bool GetSetEffectiveStateRight(Comment comment)
		{
			return GetSetEffectiveStateRight(comment, false);
		}
		#endregion
	}




	/// <summary>
	/// Comments 类后台管理部分。
	/// </summary>
	public static partial class Comments
	{
		public static bool GetManageListRight()
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			return dc.AccessController.GetUserIsHasPermission<object>(Users.CurrentUserName, null, Comments.ResourceId, (int)Comments.PermissionCode.Setting, App.Context.CurrentSiteId);
		}

		public static bool GetManageListRight(int? siteId)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			return dc.AccessController.GetUserIsHasPermission<object>(Users.CurrentUserName, null, Comments.ResourceId, (int)Comments.PermissionCode.Setting, siteId);
		}



		public class CommentForManageList
		{
			public int CommentId { get; set; }
			public string InfoType { get; set; }
			public string InfoId { get; set; }
			public string Content { get; set; }
			public bool IsEffective { get; set; }
			public DateTime PostTime { get; set; }
			public string PostIp { get; set; }
			public bool IsAnonymity { get; set; }
		}

		public static PaginationInfo<List<CommentForManageList>> GetPaginationManageList(int? siteId, string infoType, string infoId, bool? isEffective, DateTime? startTime, DateTime? endTime, string keyword, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			var q = from p in dc.Comments
					select p;

			if (siteId.HasValue)
				q = q.Where(p => p.SiteId == siteId.Value);

			if (!string.IsNullOrEmpty(infoType))
				q = q.Where(p => p.InfoType == infoType);

			if (!string.IsNullOrEmpty(infoId))
				q = q.Where(p => p.InfoId == infoId);

			if (isEffective.HasValue)
				q = q.Where(p => p.IsEffective == isEffective.Value);

			if (startTime.HasValue)
				q = q.Where(p => p.PostTime >= startTime.Value);

			if (endTime.HasValue)
				q = q.Where(p => p.PostTime <= endTime.Value);

			if (!string.IsNullOrEmpty(keyword))
				q = q.Where(p => p.Content.Contains(keyword));

			var q2 = q.Select(p => new CommentForManageList { CommentId = p.CommentId, InfoType = p.InfoType, InfoId = p.InfoId, Content = p.Content, IsEffective = p.IsEffective, PostTime = p.PostTime, PostIp = p.PostIp }).OrderByDescending(p => p.PostTime);

			PaginationInfo<List<CommentForManageList>> pageInfo = new PaginationInfo<List<CommentForManageList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q2.Count();
			pageInfo.Records = q2.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}
	}




	/// <summary>
	/// Comments 类前台显示部分。
	/// </summary>
	public static partial class Comments
	{
		public struct CommentForClientList
		{
			public int CommentId { get; set; }
			public string InfoType { get; set; }
			public string InfoId { get; set; }
			public string Content { get; set; }
			public string Quote { get; set; }
			public string PostIp { get; set; }
			public DateTime PostTime { get; set; }
			public int? SiteId { get; set; }
			public string UserName { get; set; }
			public bool IsAnonymity { get; set; }
		}



		private static IQueryable<CommentForClientList> GetListQuery(GenericModuleDataContext dc, int? siteId, string infoType, string infoId)
		{
			var q = from p in dc.Comments
					join p2 in dc.Users on p.CreatorId equals p2.UserId into p3
					from p4 in p3.DefaultIfEmpty()
					orderby p.CommentId descending,p.PostTime descending
					select new CommentForClientList
					{
						CommentId = p.CommentId,
						InfoType = p.InfoType,
						InfoId = p.InfoId,
						Content = p.Content,
						Quote = p.Quote,
						PostIp = p.PostIp,
						PostTime = p.PostTime,
						SiteId = p.SiteId,
						UserName = p4.UserName,
						IsAnonymity=p.IsAnonymity
					};

			if (siteId.HasValue)
			{
				q = q.Where(p => p.SiteId == siteId.Value);
			}

			if (!string.IsNullOrEmpty(infoType))
			{
				q = q.Where(p => p.InfoType == infoType);
			}

			if (!string.IsNullOrEmpty(infoId))
			{
				q = q.Where(p => p.InfoId == infoId);
			}

			return q.OrderByDescending(p => p.PostTime);
		}


		public static PaginationInfo<List<CommentForClientList>> GetPaginationList(int? siteId, string infoType, string infoId, int pageSize, int currentPage)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<CommentForClientList> q = GetListQuery(dc, siteId, infoType, infoId);

			PaginationInfo<List<CommentForClientList>> pageInfo = new PaginationInfo<List<CommentForClientList>>();
			pageInfo.PageSize = pageSize;
			pageInfo.CurrentPage = currentPage;
			pageInfo.RecordCount = q.Count();
			pageInfo.Records = q.Skip((currentPage - 1) * pageSize).Take(pageSize).ToList();
			return pageInfo;
		}

		public static List<CommentForClientList> GetList(int? siteId, string infoType, string infoId, int? loadCount)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<CommentForClientList> q = GetListQuery(dc, siteId, infoType, infoId);

			if (loadCount.HasValue)
				return q.Take(loadCount.Value).ToList();
			return q.ToList();
		}

		public static List<CommentForClientList> GetCommentList(int? siteId, string infoType, string infoId, int? loadCount)
		{
			GenericModuleDataContext dc = new GenericModuleDataContext();
			dc.ObjectTrackingEnabled = false;

			IQueryable<CommentForClientList> q = GetListQuery(dc, siteId, infoType, infoId);

			var q2 = from p in q
					 orderby p.CommentId descending
					 group p by new { p.InfoId, p.InfoType } into g
					 select new CommentForClientList
					 {
						 CommentId =g.Max(p=>p.CommentId),
						 InfoType = g.FirstOrDefault().InfoType,
						 InfoId = g.FirstOrDefault().InfoId,
						 Content = g.FirstOrDefault().Content,
						 Quote = g.FirstOrDefault().Quote,
						 PostIp = g.FirstOrDefault().PostIp,
						 PostTime = g.FirstOrDefault().PostTime,
						 SiteId = g.FirstOrDefault().SiteId,
						 UserName = g.FirstOrDefault().UserName,
						 IsAnonymity=g.FirstOrDefault().IsAnonymity
					 };
			q2 = q2.OrderByDescending(p => p.CommentId);

			if (loadCount.HasValue)
				return q2.Take(loadCount.Value).ToList();
			return q2.ToList();
		}


	}
}